package com.pie4cloud.pie.dmz.handler;

import com.alibaba.fastjson.JSONObject;

import com.pie4cloud.pie.dmz.entty.FileInfo;
import com.pie4cloud.pie.dmz.entty.TransferInfo;
import com.pie4cloud.pie.dmz.entty.constant.ConstantValue;
import com.pie4cloud.pie.dmz.entty.enums.MsgTypeEnum;
import com.pie4cloud.pie.dmz.entty.netty.Message;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @title: NettyClientUploadHandle
 * @Author fanml
 * @describe: //TODO
 * @Date: 2021/7/4 17:39
 * @Version 1.0
 */
public class NettyClientUploadHandler extends ChannelInboundHandlerAdapter {

	private File file;//上传的文件

	private int blockIndex;//当前块号

	private FileChannel localFileChannel;//本地文件管道

	private int blockCount;//文件总块数

	private ChannelHandlerContext ctx;//上下文

	private TransferInfo transferInfo;

	/**
	 * @param filePath 要上传的文件路径
	 * @return
	 * @throws FileNotFoundException
	 * @author fanml
	 * @date 2021/7/4 17:39
	 */
	public NettyClientUploadHandler(TransferInfo transferInfo) throws FileNotFoundException {
        this.transferInfo=transferInfo;
		file = new File(transferInfo.getFilePath());
		if (!file.exists())
			throw new FileNotFoundException(transferInfo.getFilePath());
		RandomAccessFile r = new RandomAccessFile(file, "r");
		localFileChannel = r.getChannel();
		long fileLength = file.length();
		blockCount = (int) (fileLength % ConstantValue.BLOCK_SIZE == 0 ? fileLength / ConstantValue.BLOCK_SIZE : fileLength / ConstantValue.BLOCK_SIZE + 1);

	}


	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		this.ctx = ctx;
	}

	/**
	 * 连接建立
	 *
	 * @param ctx
	 * @return
	 * @throws
	 * @author fanml
	 * @date 2021/7/4 17:41
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		//建立连接发送第一块
		putMaxFile(1);
	}

	/**
	 * 收到消息的逻辑
	 *
	 * @param ctx
	 * @param msg
	 * @return
	 * @throws Exception
	 * @author fanml
	 * @date 2021/7/4 17:42
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

		if (!(msg instanceof Message)) {
			return;
		}
		Message message = null;
		try {
			message = (Message) msg;
			//会话id
			String sessionId = message.getSessionId();
			if (MsgTypeEnum.UPLOAD == message.getMsgTypeEnum()) {
				byte[] msgBody = message.getMsgBody();
				String s = new String(msgBody, CharsetUtil.UTF_8);
				JSONObject respJson = JSONObject.parseObject(s);
				if (respJson.getInteger("retCode") == 0) {
					//获取服务端返回的块号
					blockIndex = respJson.getInteger("data").intValue();
					//上传文件块
					putMaxFile(blockIndex);
				}
			} else if (MsgTypeEnum.RESPONSE == message.getMsgTypeEnum()) {
				if (blockIndex == blockCount) {
					System.out.println("文件: " + file.getPath() + "已推送结束");
					localFileChannel.close();
					ctx.close();
				}
			}
		} finally {
			if (message != null)
				ReferenceCountUtil.release(message);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		System.out.println("发生异常了----------------------------");
		cause.printStackTrace();
		ctx.close();
	}

	/**
	 * 上传文件
	 *
	 * @param blockIndex 文件块号
	 * @return void
	 * @throws IOException
	 * @author fanml
	 * @date 2021/7/4 17:45
	 */
	private void putMaxFile(int blockIndex) throws IOException {

		MappedByteBuffer mappedByteBuffer;
		Message message;
		byte[] fileBlockByte;
		System.out.println("当前推送文件块号: " + blockIndex + "/" + blockCount);
		//文件分块起始位置
		long position = (blockIndex - 1) * ConstantValue.BLOCK_SIZE;
		//文件块长度
		long size = blockIndex == blockCount ? file.length() - (blockIndex - 1) * ConstantValue.BLOCK_SIZE : ConstantValue.BLOCK_SIZE;
		mappedByteBuffer = localFileChannel.map(FileChannel.MapMode.READ_ONLY, position, size);
		fileBlockByte = new byte[(int) size];
		for (int offset = 0; offset < size; offset++) {
			byte b = mappedByteBuffer.get();
			fileBlockByte[offset] = b;
		}
		FileInfo fileInfo = new FileInfo(transferInfo.getFileName(), file.length(), blockCount, blockIndex, fileBlockByte);
		fileInfo.setDmzPath(transferInfo.getDmzPath());
		fileInfo.setFilePath(transferInfo.getFilePath());
		fileInfo.setTargetPath(transferInfo.getTargetPath());
		fileInfo.setFtpAddress(transferInfo.getFtpAddress());
		fileInfo.setFtpUserName(transferInfo.getFtpUserName());
		fileInfo.setFtpPwd(transferInfo.getFtpPwd());
		fileInfo.setFtpPort(transferInfo.getFtpPort());
		String jsonString = JSONObject.toJSONString(fileInfo);
		message = new Message(null, MsgTypeEnum.UPLOAD, jsonString.getBytes(CharsetUtil.UTF_8));
		ctx.writeAndFlush(message);
		mappedByteBuffer.clear();
	}
}
